package com.sunwayworld.basemodule.common.asynctask.config;

import com.alibaba.fastjson.JSON;
import com.sunwayworld.basemodule.common.asynctask.comsumer.AsyncTaskRunnable;
import com.sunwayworld.basemodule.common.asynctask.util.AsyncTaskExecutorHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.*;

public class LimsAsyncTaskExecutor extends ThreadPoolExecutor {
    private static final Logger logger = LogManager.getLogger(LimsAsyncTaskExecutor.class);

    private List<Long> runningAsyncTaskIds;

    private String name;
    private static long keepAliveSeconds = 0;


    public LimsAsyncTaskExecutor(String name, int corePoolSize, int maxPoolSize,int queueCapacity) {
        super(corePoolSize, maxPoolSize, keepAliveSeconds, TimeUnit.SECONDS,new LinkedBlockingQueue<>(queueCapacity),
                new LimsNamedThreadFactory(AsyncTaskExecutorHelper.AsyncTaskExecutorNamePrefix+name+"-"), new DiscardPolicy(){
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                        //队列满，或者其他异常时
                        logger.error("rejectedExecution={}",e);
                        throw new RejectedExecutionException(name+"队列已满，拒绝加入");
                    }
                });
        this.name = AsyncTaskExecutorHelper.AsyncTaskExecutorNamePrefix+name;
        runningAsyncTaskIds = new LinkedList<>();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        try{
            AsyncTaskRunnable taskRunnable = getOriWork(r);
            if(taskRunnable!=null){
                runningAsyncTaskIds.add(taskRunnable.getServerTask().getId());
            }
        }catch (Exception s){
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        try{
            AsyncTaskRunnable taskRunnable = getOriWork(r);
            if(taskRunnable!=null){
                runningAsyncTaskIds.remove(taskRunnable.getServerTask().getId());
            }
        }catch (Exception s){
        }
    }

    public String getName() {
        return name;
    }

    /**
     * 【核心方法】从FutureTask获取原始的任务对象
     * @param futureTask
     */
    private <T> T getOriWork(Object futureTask) {
        boolean isFutureTask = futureTask instanceof FutureTask;
        if (!isFutureTask) {
            throw new RuntimeException("不是FutureTask 无法获取原始任务：" + JSON.toJSONString(futureTask));
        }
        try {
            // 获取 FutureTask.callable
            Field callableField = FutureTask.class.getDeclaredField("callable");
            callableField.setAccessible(true);
            Object callableObj = callableField.get(futureTask);
            if(callableObj==null){
                return  null;
            }
            // 获取 上一步callable的数据类型：Executors的内部类RunnableAdapter
            Class<?>[] classes = Executors.class.getDeclaredClasses();
            Class tarClass = null;
            for (Class<?> cls : classes) {
                if (cls.getName().equals("java.util.concurrent.Executors$RunnableAdapter")) {
                    tarClass = cls;
                    break;
                }
            }
            // 获取原始任务对象
            Field taskField = tarClass.getDeclaredField("task");
            taskField.setAccessible(true);
            return  (T)taskField.get(callableObj);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException("从FutureTask获取原始任务对象失败", e);
        }
    }
}
